Bytecode = function () {
    console.log("init")
};

//程序计数器
class Program_counter {
    constructor() {
        this.code = null;
        this.ptr = 0;
    }

    first() {
        this.ptr = 0;
    }

    current() {
        return this.code[this.ptr];
    }

    add(i) {
        this.ptr += i;
    }

    increment(delta) {
        delta = delta || 1;
        this.add(delta);
        console.log("---------------------------------")
        console.log(frameData.operand_stack)
        console.log(frameData.local_variables)
        console.log("---------------------------------")
    }

    set(pos) {
        //todo check
        if (pos < this.code.length) {
            this.ptr = pos;
        }

        console.log("---------------------------------")
        console.log(frameData.operand_stack)
        console.log(frameData.local_variables)
        console.log("---------------------------------")
    }

    next() {
        return this.code[++this.ptr];
    }
}


Bytecode.init_bytecode_handler_table = function (handlerTable) {
    //理论上最多256个字节码，每个字节码处理函数指针先初始化为空。
    const TABLE_SIZE = 256;
    // for (let i = 0; i < TABLE_SIZE; i++) {
    //     handlerTable[i].code = i;
    //     handlerTable[i].handler = null;
    // }

    //接下来为每个字节码设置处理函数。
    //这张表希望有256项，需要仔细照顾。
    let table = [
        {code: 0, opcode: "nop", handler: Bytecode.handle_nop},
        {code: 1, opcode: "aconst_null", handler: Bytecode.handle_aconst_null},
        {code: 2, opcode: "iconst_m1", handler: Bytecode.handle_iconst_m1},
        {code: 3, opcode: "iconst_0", handler: Bytecode.handle_iconst_0},
        {code: 4, opcode: "iconst_1", handler: Bytecode.handle_iconst_1},
        {code: 5, opcode: "iconst_2", handler: Bytecode.handle_iconst_2},
        {code: 6, opcode: "iconst_3", handler: Bytecode.handle_iconst_3},
        {code: 7, opcode: "iconst_4", handler: Bytecode.handle_iconst_4},
        {code: 8, opcode: "iconst_5", handler: Bytecode.handle_iconst_5},
        {code: 9, opcode: "lconst_0", handler: Bytecode.handle_lconst_0},
        {code: 10, opcode: "lconst_1", handler: Bytecode.handle_lconst_1},
        {code: 11, opcode: "fconst_0", handler: Bytecode.handle_fconst_0},
        {code: 12, opcode: "fconst_1", handler: Bytecode.handle_fconst_1},
        {code: 13, opcode: "fconst_2", handler: Bytecode.handle_fconst_2},
        {code: 14, opcode: "dconst_0", handler: Bytecode.handle_dconst_0},
        {code: 15, opcode: "dconst_1", handler: Bytecode.handle_dconst_1},
        {code: 16, opcode: "bipush", handler: Bytecode.handle_bipush},
        {code: 17, opcode: "sipush", handler: Bytecode.handle_sipush},
        {code: 18, opcode: "ldc", handler: Bytecode.handle_ldc},
        {code: 19, opcode: "ldc_w", handler: Bytecode.handle_ldc_w},
        {code: 20, opcode: "ldc2_w", handler: Bytecode.handle_ldc2_w},
        {code: 21, opcode: "iload", handler: Bytecode.handle_iload},
        {code: 22, opcode: "lload", handler: Bytecode.handle_lload},
        {code: 23, opcode: "fload", handler: Bytecode.handle_fload},
        {code: 24, opcode: "dload", handler: Bytecode.handle_dload},
        {code: 25, opcode: "aload", handler: Bytecode.handle_aload},
        {code: 26, opcode: "iload_0", handler: Bytecode.handle_iload_0},
        {code: 27, opcode: "iload_1", handler: Bytecode.handle_iload_1},
        {code: 28, opcode: "iload_2", handler: Bytecode.handle_iload_2},
        {code: 29, opcode: "iload_3", handler: Bytecode.handle_iload_3},
        {code: 30, opcode: "lload_0", handler: Bytecode.handle_lload_0},
        {code: 31, opcode: "lload_1", handler: Bytecode.handle_lload_1},
        {code: 32, opcode: "lload_2", handler: Bytecode.handle_lload_2},
        {code: 33, opcode: "lload_3", handler: Bytecode.handle_lload_3},
        {code: 34, opcode: "fload_0", handler: Bytecode.handle_fload_0},
        {code: 35, opcode: "fload_1", handler: Bytecode.handle_fload_1},
        {code: 36, opcode: "fload_2", handler: Bytecode.handle_fload_2},
        {code: 37, opcode: "fload_3", handler: Bytecode.handle_fload_3},
        {code: 38, opcode: "dload_0", handler: Bytecode.handle_dload_0},
        {code: 39, opcode: "dload_1", handler: Bytecode.handle_dload_1},
        {code: 40, opcode: "dload_2", handler: Bytecode.handle_dload_2},
        {code: 41, opcode: "dload_3", handler: Bytecode.handle_dload_3},
        {code: 42, opcode: "aload_0", handler: Bytecode.handle_aload_0},
        {code: 43, opcode: "aload_1", handler: Bytecode.handle_aload_1},
        {code: 44, opcode: "aload_2", handler: Bytecode.handle_aload_2},
        {code: 45, opcode: "aload_3", handler: Bytecode.handle_aload_3},
        {code: 46, opcode: "iaload", handler: Bytecode.handle_iaload},
        {code: 47, opcode: "laload", handler: Bytecode.handle_laload},
        {code: 48, opcode: "faload", handler: Bytecode.handle_faload},
        {code: 49, opcode: "daload", handler: Bytecode.handle_daload},
        {code: 50, opcode: "aaload", handler: Bytecode.handle_aaload},
        {code: 51, opcode: "baload", handler: Bytecode.handle_baload},
        {code: 52, opcode: "caload", handler: Bytecode.handle_caload},
        {code: 53, opcode: "saload", handler: Bytecode.handle_saload},
        {code: 54, opcode: "istore", handler: Bytecode.handle_istore},
        {code: 55, opcode: "lstore", handler: Bytecode.handle_lstore},
        {code: 56, opcode: "fstore", handler: Bytecode.handle_fstore},
        {code: 57, opcode: "dstore", handler: Bytecode.handle_dstore},
        {code: 58, opcode: "astore", handler: Bytecode.handle_astore},
        {code: 59, opcode: "istore_0", handler: Bytecode.handle_istore_0},
        {code: 60, opcode: "istore_1", handler: Bytecode.handle_istore_1},
        {code: 61, opcode: "istore_2", handler: Bytecode.handle_istore_2},
        {code: 62, opcode: "istore_3", handler: Bytecode.handle_istore_3},
        {code: 63, opcode: "lstore_0", handler: Bytecode.handle_lstore_0},
        {code: 64, opcode: "lstore_1", handler: Bytecode.handle_lstore_1},
        {code: 65, opcode: "lstore_2", handler: Bytecode.handle_lstore_2},
        {code: 66, opcode: "lstore_3", handler: Bytecode.handle_lstore_3},
        {code: 67, opcode: "fstore_0", handler: Bytecode.handle_fstore_0},
        {code: 68, opcode: "fstore_1", handler: Bytecode.handle_fstore_1},
        {code: 69, opcode: "fstore_2", handler: Bytecode.handle_fstore_2},
        {code: 70, opcode: "fstore_3", handler: Bytecode.handle_fstore_3},
        {code: 71, opcode: "dstore_0", handler: Bytecode.handle_dstore_0},
        {code: 72, opcode: "dstore_1", handler: Bytecode.handle_dstore_1},
        {code: 73, opcode: "dstore_2", handler: Bytecode.handle_dstore_2},
        {code: 74, opcode: "dstore_3", handler: Bytecode.handle_dstore_3},
        {code: 75, opcode: "astore_0", handler: Bytecode.handle_astore_0},
        {code: 76, opcode: "astore_1", handler: Bytecode.handle_astore_1},
        {code: 77, opcode: "astore_2", handler: Bytecode.handle_astore_2},
        {code: 78, opcode: "astore_3", handler: Bytecode.handle_astore_3},
        {code: 79, opcode: "iastore", handler: Bytecode.handle_iastore},
        {code: 80, opcode: "lastore", handler: Bytecode.handle_lastore},
        {code: 81, opcode: "fastore", handler: Bytecode.handle_fastore},
        {code: 82, opcode: "dastore", handler: Bytecode.handle_dastore},
        {code: 83, opcode: "aastore", handler: Bytecode.handle_aastore},
        {code: 84, opcode: "bastore", handler: Bytecode.handle_bastore},
        {code: 85, opcode: "castore", handler: Bytecode.handle_castore},
        {code: 86, opcode: "sastore", handler: Bytecode.handle_sastore},
        {code: 87, opcode: "pop", handler: Bytecode.handle_pop},
        {code: 88, opcode: "pop2", handler: Bytecode.handle_pop2},
        {code: 89, opcode: "dup", handler: Bytecode.handle_dup},
        {code: 90, opcode: "dup_x1", handler: Bytecode.handle_dup_x1},
        {code: 91, opcode: "dup_x2", handler: Bytecode.handle_dup_x2},
        {code: 92, opcode: "dup2", handler: Bytecode.handle_dup2},
        {code: 93, opcode: "dup2_x1", handler: Bytecode.handle_dup2_x1},
        {code: 94, opcode: "dup2_x2", handler: Bytecode.handle_dup2_x2},
        {code: 95, opcode: "swap", handler: Bytecode.handle_swap},
        {code: 96, opcode: "iadd", handler: Bytecode.handle_iadd},
        {code: 97, opcode: "ladd", handler: Bytecode.handle_ladd},
        {code: 98, opcode: "fadd", handler: Bytecode.handle_fadd},
        {code: 99, opcode: "dadd", handler: Bytecode.handle_dadd},
        {code: 100, opcode: "isub", handler: Bytecode.handle_isub},
        {code: 101, opcode: "lsub", handler: Bytecode.handle_lsub},
        {code: 102, opcode: "fsub", handler: Bytecode.handle_fsub},
        {code: 103, opcode: "dsub", handler: Bytecode.handle_dsub},
        {code: 104, opcode: "imul", handler: Bytecode.handle_imul},
        {code: 105, opcode: "lmul", handler: Bytecode.handle_lmul},
        {code: 106, opcode: "fmul", handler: Bytecode.handle_fmul},
        {code: 107, opcode: "dmul", handler: Bytecode.handle_dmul},
        {code: 108, opcode: "idiv", handler: Bytecode.handle_idiv},
        {code: 109, opcode: "ldiv", handler: Bytecode.handle_ldiv},
        {code: 110, opcode: "fdiv", handler: Bytecode.handle_fdiv},
        {code: 111, opcode: "ddiv", handler: Bytecode.handle_ddiv},
        {code: 112, opcode: "irem", handler: Bytecode.handle_irem},
        {code: 113, opcode: "lrem", handler: Bytecode.handle_lrem},
        {code: 114, opcode: "frem", handler: Bytecode.handle_frem},
        {code: 115, opcode: "drem", handler: Bytecode.handle_drem},
        {code: 116, opcode: "ineg", handler: Bytecode.handle_ineg},
        {code: 117, opcode: "lneg", handler: Bytecode.handle_lneg},
        {code: 118, opcode: "fneg", handler: Bytecode.handle_fneg},
        {code: 119, opcode: "dneg", handler: Bytecode.handle_dneg},
        {code: 120, opcode: "ishl", handler: Bytecode.handle_ishl},
        {code: 121, opcode: "lshl", handler: Bytecode.handle_lshl},
        {code: 122, opcode: "ishr", handler: Bytecode.handle_ishr},
        {code: 123, opcode: "lshr", handler: Bytecode.handle_lshr},
        {code: 124, opcode: "iushr", handler: Bytecode.handle_iushr},
        {code: 125, opcode: "lushr", handler: Bytecode.handle_lushr},
        {code: 126, opcode: "iand", handler: Bytecode.handle_iand},
        {code: 127, opcode: "land", handler: Bytecode.handle_land},
        {code: 128, opcode: "ior", handler: Bytecode.handle_ior},
        {code: 129, opcode: "lor", handler: Bytecode.handle_lor},
        {code: 130, opcode: "ixor", handler: Bytecode.handle_ixor},
        {code: 131, opcode: "lxor", handler: Bytecode.handle_lxor},
        {code: 132, opcode: "iinc", handler: Bytecode.handle_iinc},
        {code: 133, opcode: "i2l", handler: Bytecode.handle_i2l},
        {code: 134, opcode: "i2f", handler: Bytecode.handle_i2f},
        {code: 135, opcode: "i2d", handler: Bytecode.handle_i2d},
        {code: 136, opcode: "l2i", handler: Bytecode.handle_l2i},
        {code: 137, opcode: "l2f", handler: Bytecode.handle_l2f},
        {code: 138, opcode: "l2d", handler: Bytecode.handle_l2d},
        {code: 139, opcode: "f2i", handler: Bytecode.handle_f2i},
        {code: 140, opcode: "f2l", handler: Bytecode.handle_f2l},
        {code: 141, opcode: "f2d", handler: Bytecode.handle_f2d},
        {code: 142, opcode: "d2i", handler: Bytecode.handle_d2i},
        {code: 143, opcode: "d2l", handler: Bytecode.handle_d2l},
        {code: 144, opcode: "d2f", handler: Bytecode.handle_d2f},
        {code: 145, opcode: "i2b", handler: Bytecode.handle_i2b},
        {code: 146, opcode: "i2c", handler: Bytecode.handle_i2c},
        {code: 147, opcode: "i2s", handler: Bytecode.handle_i2s},
        {code: 148, opcode: "lcmp", handler: Bytecode.handle_lcmp},
        {code: 149, opcode: "fcmpl", handler: Bytecode.handle_fcmpl},
        {code: 150, opcode: "fcmpg", handler: Bytecode.handle_fcmpg},
        {code: 151, opcode: "dcmpl", handler: Bytecode.handle_dcmpl},
        {code: 152, opcode: "dcompg", handler: Bytecode.handle_dcompg},
        {code: 153, opcode: "ifeq", handler: Bytecode.handle_ifeq},
        {code: 154, opcode: "ifne", handler: Bytecode.handle_ifne},
        {code: 155, opcode: "iflt", handler: Bytecode.handle_iflt},
        {code: 156, opcode: "ifge", handler: Bytecode.handle_ifge},
        {code: 157, opcode: "ifgt", handler: Bytecode.handle_ifgt},
        {code: 158, opcode: "ifle", handler: Bytecode.handle_ifle},
        {code: 159, opcode: "if_icmpeq", handler: Bytecode.handle_if_icmpeq},
        {code: 160, opcode: "if_icmpne", handler: Bytecode.handle_if_icmpne},
        {code: 161, opcode: "if_icmplt", handler: Bytecode.handle_if_icmplt},
        {code: 162, opcode: "if_icmpge", handler: Bytecode.handle_if_icmpge},
        {code: 163, opcode: "if_icmpgt", handler: Bytecode.handle_if_icmpgt},
        {code: 164, opcode: "if_icmple", handler: Bytecode.handle_if_icmple},
        {code: 165, opcode: "if_acmpeq", handler: Bytecode.handle_if_acmpeq},
        {code: 166, opcode: "if_acmpne", handler: Bytecode.handle_if_acmpne},
        {code: 167, opcode: "goto", handler: Bytecode.handle_goto},
        {code: 168, opcode: "jsr", handler: Bytecode.handle_jsr},
        {code: 169, opcode: "ret", handler: Bytecode.handle_ret},
        {code: 170, opcode: "tableswitch", handler: Bytecode.handle_tableswitch},
        {code: 171, opcode: "lookupswitch", handler: Bytecode.handle_lookupswitch},
        {code: 172, opcode: "ireturn", handler: Bytecode.handle_ireturn},
        {code: 173, opcode: "lreturn", handler: Bytecode.handle_lreturn},
        {code: 174, opcode: "freturn", handler: Bytecode.handle_freturn},
        {code: 175, opcode: "dreturn", handler: Bytecode.handle_dreturn},
        {code: 176, opcode: "areturn", handler: Bytecode.handle_areturn},
        {code: 177, opcode: "return", handler: Bytecode.handle_return},
        {code: 178, opcode: "getstatic", handler: Bytecode.handle_getstatic},
        {code: 179, opcode: "putstatic", handler: Bytecode.handle_putstatic},
        {code: 180, opcode: "getfield", handler: Bytecode.handle_getfield},
        {code: 181, opcode: "putfield", handler: Bytecode.handle_putfield},
        {code: 182, opcode: "invokevirtual", handler: Bytecode.handle_invokevirtual},
        {code: 183, opcode: "invokespecial", handler: Bytecode.handle_invokespecial},
        {code: 184, opcode: "invokestatic", handler: Bytecode.handle_invokestatic},
        {code: 185, opcode: "invokeinterface", handler: Bytecode.handle_invokeinterface},
        {code: 186, opcode: "186", handler: null},//xxxunusedxxx
        {code: 187, opcode: "new", handler: Bytecode.handle_new},
        {code: 188, opcode: "newarray", handler: Bytecode.handle_newarray},
        {code: 189, opcode: "anewarray", handler: Bytecode.handle_anewarray},
        {code: 190, opcode: "arraylength", handler: Bytecode.handle_arraylength},
        {code: 191, opcode: "athrow", handler: Bytecode.handle_athrow},
        {code: 192, opcode: "checkcast", handler: Bytecode.handle_checkcast},
        {code: 193, opcode: "instanceof", handler: Bytecode.handle_instanceof},
        {code: 194, opcode: "monitorenter", handler: Bytecode.handle_monitorenter},
        {code: 195, opcode: "monitorexit", handler: Bytecode.handle_monitorexit},
        {code: 196, opcode: "wide", handler: Bytecode.handle_wide},
        {code: 197, opcode: "multianewarray", handler: Bytecode.handle_multianewarray},
        {code: 198, opcode: "ifnull", handler: Bytecode.handle_ifnull},
        {code: 199, opcode: "ifnonnull", handler: Bytecode.handle_ifnonnull},
        {code: 200, opcode: "goto_w", handler: Bytecode.handle_goto_w},
        {code: 201, opcode: "jsr_w", handler: Bytecode.handle_jsr_w},
        {code: 202, opcode: "breakpoin", handler: Bytecode.handle_breakpoint},
        {code: 203, opcode: "203", handler: null},
        {code: 204, opcode: "204", handler: null},
        {code: 205, opcode: "205", handler: null},
        {code: 206, opcode: "206", handler: null},
        {code: 207, opcode: "207", handler: null},
        {code: 208, opcode: "208", handler: null},
        {code: 209, opcode: "209", handler: null},
        {code: 210, opcode: "210", handler: null},
        {code: 211, opcode: "211", handler: null},
        {code: 212, opcode: "212", handler: null},
        {code: 213, opcode: "213", handler: null},
        {code: 214, opcode: "214", handler: null},
        {code: 215, opcode: "215", handler: null},
        {code: 216, opcode: "216", handler: null},
        {code: 217, opcode: "217", handler: null},
        {code: 218, opcode: "218", handler: null},
        {code: 219, opcode: "219", handler: null},
        {code: 220, opcode: "220", handler: null},
        {code: 221, opcode: "221", handler: null},
        {code: 222, opcode: "222", handler: null},
        {code: 223, opcode: "223", handler: null},
        {code: 224, opcode: "224", handler: null},
        {code: 225, opcode: "225", handler: null},
        {code: 226, opcode: "226", handler: null},
        {code: 227, opcode: "227", handler: null},
        {code: 228, opcode: "228", handler: null},
        {code: 229, opcode: "229", handler: null},
        {code: 230, opcode: "230", handler: null},
        {code: 231, opcode: "231", handler: null},
        {code: 232, opcode: "232", handler: null},
        {code: 233, opcode: "233", handler: null},
        {code: 234, opcode: "234", handler: null},
        {code: 235, opcode: "235", handler: null},
        {code: 236, opcode: "236", handler: null},
        {code: 237, opcode: "237", handler: null},
        {code: 238, opcode: "238", handler: null},
        {code: 239, opcode: "239", handler: null},
        {code: 240, opcode: "240", handler: null},
        {code: 241, opcode: "241", handler: null},
        {code: 242, opcode: "242", handler: null},
        {code: 243, opcode: "243", handler: null},
        {code: 244, opcode: "244", handler: null},
        {code: 245, opcode: "245", handler: null},
        {code: 246, opcode: "246", handler: null},
        {code: 247, opcode: "247", handler: null},
        {code: 248, opcode: "248", handler: null},
        {code: 249, opcode: "249", handler: null},
        {code: 250, opcode: "250", handler: null},
        {code: 251, opcode: "251", handler: null},
        {code: 252, opcode: "252", handler: null},
        {code: 253, opcode: "253", handler: null},
        {code: 254, opcode: "impdep1", handler: Bytecode.handle_impdep1},
        {code: 255, opcode: "impdep2", handler: Bytecode.handle_impdep2}
    ];

    for (let i = 0; i < TABLE_SIZE; i++) {
        //检查字节码表是否有疏忽或遗漏
        if (table[i].code != i)
            return false;
        handlerTable[i] = table[i];
    }

    return true;
}

Bytecode.handle_nop = function () {
}

Bytecode.handle_aconst_null = function () {

}

Bytecode.handle_iconst_m1 = function () {

}

Bytecode.handle_iconst_0 = function () {
    //将int类型常量0压栈
    Bytecode.push_int(0);
}

Bytecode.handle_iconst_1 = function () {
    //将int类型常量1压栈
    Bytecode.push_int(1);
    _program_counter.increment();
}

Bytecode.handle_iconst_2 = function () {
    //将int类型常量2压栈
    Bytecode.push_int(2);
    _program_counter.increment();
}

Bytecode.handle_iconst_3 = function () {
    //将int类型常量3压栈
    Bytecode.push_int(3);
    _program_counter.increment();
}

Bytecode.handle_iconst_4 = function () {
    //将int类型常量4压栈
    Bytecode.push_int(4);
    _program_counter.increment();
}

Bytecode.handle_iconst_5 = function () {
    //将int类型常量5压栈
    Bytecode.push_int(5);
    _program_counter.increment();
}

Bytecode.handle_lconst_0 = function () {

}

Bytecode.handle_lconst_1 = function () {

}

Bytecode.handle_fconst_0 = function () {

}

Bytecode.handle_fconst_1 = function () {

}

Bytecode.handle_fconst_2 = function () {

}

Bytecode.handle_dconst_0 = function () {

}

Bytecode.handle_dconst_1 = function () {

}

Bytecode.handle_bipush = function () {
    let i = _program_counter.next();

    //处理负数符号位
    //http://stackoverflow.com/questions/13468474/javascript-convert-a-hex-signed-integer-to-a-javascript-value
    i = parseInt(i, 10);
    if ((i & 0x80) > 0) {
        i = i - 0x100;
    }

    frameData.operand_stack.push(i);
    _program_counter.increment();
}

Bytecode.handle_sipush = function () {
    let i = _program_counter.next() << 8 | _program_counter.next();

    //todo 测试负数
    i = parseInt(i, 10);
    if ((i & 0x8000) > 0) {
        i = i - 0x10000;
    }

    frameData.operand_stack.push(i);
    _program_counter.increment();
}

Bytecode.handle_ldc = function () {
//Todo: 检查常量池的索引是否有效，是放在这里，即指令执行的地方，
    //还是放在加载class文件时，对字节码校验的地方？
    const idx = _program_counter.next();
    const constant = Bytecode.currentClass().constantPool[idx];
    const tag = constant.tag;
    switch (tag) {
        case JD.ConstantPoolTag.INTEGER:
            //todo 直接存bytes不知道是不是不够好
            frameData.operand_stack.push(constant.bytes);
            break;
        case JD.ConstantPoolTag.FLOAT:
            frameData.operand_stack.push(constant.bytes);
            break;
        //Todo: case CONSTANT_String:
        //    break;
    }
    _program_counter.increment();
}

Bytecode.handle_ldc_w = function () {

}

Bytecode.handle_ldc2_w = function () {
    const idx = _program_counter.next() << 8 | _program_counter.next();
    const constant = Bytecode.currentClass().constantPool[idx];
    const tag = constant.tag;
    switch (tag) {
        case JD.ConstantPoolTag.LONG:
            //todo 这里是低位在下
            frameData.operand_stack.push(constant.lowBytes);
            frameData.operand_stack.push(constant.highBytes);
            break;
        case JD.ConstantPoolTag.DOUBLE:
            frameData.operand_stack.push(constant.lowBytes);
            frameData.operand_stack.push(constant.highBytes);
            break;
        //Todo: case CONSTANT_String:
        //    break;
    }
    _program_counter.increment();
}

Bytecode.handle_iload = function () {
    let idx = _program_counter.next();
    let i = frameData.local_variables[idx];
    frameData.operand_stack.push(i);
    _program_counter.increment();
}

Bytecode.handle_lload = function () {
    let idx = _program_counter.next();

    const lowBytes = frameData.local_variables[idx];
    const highBytes = frameData.local_variables[idx + 1];

    frameData.operand_stack.push(lowBytes);
    frameData.operand_stack.push(highBytes);
    console.log(frameData.operand_stack)
    _program_counter.increment();
}

Bytecode.handle_fload = function () {
    let idx = _program_counter.next();
    let i = frameData.local_variables[idx];
    frameData.operand_stack.push(i);
    _program_counter.increment();
}

Bytecode.handle_dload = function () {
    let idx = _program_counter.next();

    const lowBytes = frameData.local_variables[idx];
    const highBytes = frameData.local_variables[idx + 1];

    frameData.operand_stack.push(lowBytes);
    frameData.operand_stack.push(highBytes);
    console.log(frameData.operand_stack)
    _program_counter.increment();
}

Bytecode.handle_aload = function () {

}

Bytecode.handle_iload_0 = function () {
    //局部变量表第0个放到操作数栈中
    let i = frameData.local_variables[0];
    frameData.operand_stack.push(i);
    _program_counter.increment();
}

Bytecode.handle_iload_1 = function () {
    let i = frameData.local_variables[1];
    frameData.operand_stack.push(i);

    _program_counter.increment();
}

Bytecode.handle_iload_2 = function () {
    let i = frameData.local_variables[2];
    frameData.operand_stack.push(i);
    _program_counter.increment();

}

Bytecode.handle_iload_3 = function () {
    let i = frameData.local_variables[3];
    frameData.operand_stack.push(i);
    _program_counter.increment();
}

Bytecode.handle_lload_0 = function () {

}

Bytecode.handle_lload_1 = function () {

}

Bytecode.handle_lload_2 = function () {

}

Bytecode.handle_lload_3 = function () {

}

Bytecode.handle_fload_0 = function () {

}

Bytecode.handle_fload_1 = function () {

}

Bytecode.handle_fload_2 = function () {

}

Bytecode.handle_fload_3 = function () {

}

Bytecode.handle_dload_0 = function () {

}

Bytecode.handle_dload_1 = function () {

}

Bytecode.handle_dload_2 = function () {

}

Bytecode.handle_dload_3 = function () {

}

Bytecode.handle_aload_0 = function () {

}

Bytecode.handle_aload_1 = function () {

}

Bytecode.handle_aload_2 = function () {

}

Bytecode.handle_aload_3 = function () {

}

Bytecode.handle_iaload = function () {
}

Bytecode.handle_laload = function () {
}

Bytecode.handle_faload = function () {
}

Bytecode.handle_daload = function () {
}

Bytecode.handle_aaload = function () {
}

Bytecode.handle_baload = function () {
}

Bytecode.handle_caload = function () {
}

Bytecode.handle_saload = function () {
}

Bytecode.handle_istore = function () {
    const pos = _program_counter.next();
    frameData.local_variables[pos] = frameData.operand_stack.pop();
    _program_counter.increment();
}

Bytecode.handle_lstore = function () {
    //todo 按理说要占两个位置 不知道只用一个位置会不会有问题
    const idx = _program_counter.next();
    //todo 不知道顺序对不对
    const highBytes = frameData.operand_stack.pop();
    const lowBytes = frameData.operand_stack.pop();
    frameData.local_variables[idx] = lowBytes;
    frameData.local_variables[idx + 1] = highBytes;

    _program_counter.increment();
}

Bytecode.handle_fstore = function () {
    const idx = _program_counter.next();
    console.log(idx)
    frameData.local_variables[idx] = frameData.operand_stack.pop();
    _program_counter.increment();
}

Bytecode.handle_dstore = function () {
    //todo 按理说要占两个位置 不知道只用一个位置会不会有问题
    const idx = _program_counter.next();
    //todo 不知道顺序对不对
    const highBytes = frameData.operand_stack.pop();
    const lowBytes = frameData.operand_stack.pop();
    frameData.local_variables[idx] = lowBytes;
    frameData.local_variables[idx + 1] = highBytes;

    _program_counter.increment();
}

Bytecode.handle_astore = function () {
}

Bytecode.handle_istore_0 = function () {
    frameData.local_variables[0] = frameData.operand_stack.pop();
    _program_counter.increment();
}

Bytecode.handle_istore_1 = function () {
    frameData.local_variables[1] = frameData.operand_stack.pop();
    _program_counter.increment();
}

Bytecode.handle_istore_2 = function () {
    frameData.local_variables[2] = frameData.operand_stack.pop();
    _program_counter.increment();
}

Bytecode.handle_istore_3 = function () {
    frameData.local_variables[3] = frameData.operand_stack.pop();
    _program_counter.increment();
}

Bytecode.handle_lstore_0 = function () {
}

Bytecode.handle_lstore_1 = function () {
}

Bytecode.handle_lstore_2 = function () {
}

Bytecode.handle_lstore_3 = function () {
}

Bytecode.handle_fstore_0 = function () {
}

Bytecode.handle_fstore_1 = function () {
}

Bytecode.handle_fstore_2 = function () {
}

Bytecode.handle_fstore_3 = function () {
}

Bytecode.handle_dstore_0 = function () {
}

Bytecode.handle_dstore_1 = function () {
}

Bytecode.handle_dstore_2 = function () {
}

Bytecode.handle_dstore_3 = function () {
}

Bytecode.handle_astore_0 = function () {
}

Bytecode.handle_astore_1 = function () {
}

Bytecode.handle_astore_2 = function () {
}

Bytecode.handle_astore_3 = function () {
}

Bytecode.handle_iastore = function () {
}

Bytecode.handle_lastore = function () {
}

Bytecode.handle_fastore = function () {
}

Bytecode.handle_dastore = function () {
}

Bytecode.handle_aastore = function () {
}

Bytecode.handle_bastore = function () {
}

Bytecode.handle_castore = function () {
}

Bytecode.handle_sastore = function () {
}

Bytecode.handle_pop = function () {
}

Bytecode.handle_pop2 = function () {
}

Bytecode.handle_dup = function () {
}

Bytecode.handle_dup_x1 = function () {
}

Bytecode.handle_dup_x2 = function () {
}

Bytecode.handle_dup2 = function () {
}

Bytecode.handle_dup2_x1 = function () {
}

Bytecode.handle_dup2_x2 = function () {
}

Bytecode.handle_swap = function () {
}

Bytecode.handle_iadd = function () {
    let a = frameData.operand_stack.pop();
    let b = frameData.operand_stack.pop();
    frameData.operand_stack.push(a + b);
    _program_counter.increment();
}

Bytecode.handle_ladd = function () {
}

Bytecode.handle_fadd = function () {
}

Bytecode.handle_dadd = function () {
}

Bytecode.handle_isub = function () {
}

Bytecode.handle_lsub = function () {
}

Bytecode.handle_fsub = function () {
}

Bytecode.handle_dsub = function () {
}

Bytecode.handle_imul = function () {
}

Bytecode.handle_lmul = function () {
}

Bytecode.handle_fmul = function () {
}

Bytecode.handle_dmul = function () {
}

Bytecode.handle_idiv = function () {
}

Bytecode.handle_ldiv = function () {
}

Bytecode.handle_fdiv = function () {
}

Bytecode.handle_ddiv = function () {
}

Bytecode.handle_irem = function () {
}

Bytecode.handle_lrem = function () {
}

Bytecode.handle_frem = function () {
}

Bytecode.handle_drem = function () {
}

Bytecode.handle_ineg = function () {
}

Bytecode.handle_lneg = function () {
}

Bytecode.handle_fneg = function () {
}

Bytecode.handle_dneg = function () {
}

Bytecode.handle_ishl = function () {
}

Bytecode.handle_lshl = function () {
}

Bytecode.handle_ishr = function () {
}

Bytecode.handle_lshr = function () {
}

Bytecode.handle_iushr = function () {
}

Bytecode.handle_lushr = function () {
}

Bytecode.handle_iand = function () {
}

Bytecode.handle_land = function () {
}

Bytecode.handle_ior = function () {
}

Bytecode.handle_lor = function () {
}

Bytecode.handle_ixor = function () {
}

Bytecode.handle_lxor = function () {
}

Bytecode.handle_iinc = function () {
}

Bytecode.handle_i2l = function () {
}

Bytecode.handle_i2f = function () {
}

Bytecode.handle_i2d = function () {
}

Bytecode.handle_l2i = function () {
}

Bytecode.handle_l2f = function () {
}

Bytecode.handle_l2d = function () {
}

Bytecode.handle_f2i = function () {
}

Bytecode.handle_f2l = function () {
}

Bytecode.handle_f2d = function () {
}

Bytecode.handle_d2i = function () {
}

Bytecode.handle_d2l = function () {
}

Bytecode.handle_d2f = function () {
}

Bytecode.handle_i2b = function () {
}

Bytecode.handle_i2c = function () {
}

Bytecode.handle_i2s = function () {
}

Bytecode.handle_lcmp = function () {
    let a_high = frameData.operand_stack.pop();
    let a_low = frameData.operand_stack.pop();

    let b_high = frameData.operand_stack.pop();

    let b_low = frameData.operand_stack.pop();

    //todo 需要验证
    if (a_high > b_high) frameData.operand_stack.push(1);
    else if (a_high < b_high) frameData.operand_stack.push(-1);
    else {
        if ((a_low >>> 0) > (b_low >>> 0)) {
            frameData.operand_stack.push(1);
        } else if ((a_low >>> 0) < (b_low >>> 0)) {
            frameData.operand_stack.push(-1);
        } else {
            frameData.operand_stack.push(0);
        }
    }

    _program_counter.increment();
}

Bytecode.handle_fcmpl = function () {
    let a = Bytecode.ieee32ToFloat(frameData.operand_stack.pop());
    let b = Bytecode.ieee32ToFloat(frameData.operand_stack.pop());
    if (a > b) frameData.operand_stack.push(1);
    else if (a < b) frameData.operand_stack.push(-1);
    else frameData.operand_stack.push(0);

    _program_counter.increment();
}

Bytecode.ieee32ToFloat = function (intval) {
    let fval = 0.0;
    let x;//exponent
    let m;//mantissa
    let s;//sign
    s = (intval & 0x80000000) ? -1 : 1;
    x = ((intval >> 23) & 0xFF);
    m = (intval & 0x7FFFFF);
    switch (x) {
        case 0:
            //zero, do nothing, ignore negative zero and subnormals
            break;
        case 0xFF:
            if (m) fval = NaN;
            else if (s > 0) fval = Number.POSITIVE_INFINITY;
            else fval = Number.NEGATIVE_INFINITY;
            break;
        default:
            x -= 127;
            m += 0x800000;
            fval = s * (m / 8388608.0) * Math.pow(2, x);
            break;
    }
    return fval;
}


Bytecode.ieee64ToDouble = function (intval) {
    let str = intval.toString(2)

    let fval = 0.0;
    let x;//exponent
    let m;//mantissa
    let s;//sign
    s = (intval & 0x8000000000000000) ? -1 : 1;
    x = parseInt(str.substr(str.length - 63, str.length - 52), 2);
    m = str.substr(str.length - 52);
    switch (x) {
        case 0:
            //zero, do nothing, ignore negative zero and subnormals
            break;
        case 0xFF:
            if (m) fval = NaN;
            else if (s > 0) fval = Number.POSITIVE_INFINITY;
            else fval = Number.NEGATIVE_INFINITY;
            break;
        default:
            let delta = 1.0;
            for (let i = 0; i < m.length; i++) {
                delta += parseInt(m[i]) * Math.pow(2, -1 * (i + 1))
            }

            fval = s * Math.pow(2, x - 0x3ff) * delta;
            break;
    }
    return fval;
}

Bytecode.ieee64StrToDouble = function (str) {

    let fval = 0.0;
    let x;//exponent
    let m;//mantissa
    let s;//sign
    s = str.length == 64 ? (str[0] == '1' ? -1 : 1) : 1;
    x = parseInt(str.substr(str.length - 63, str.length - 52), 2);
    m = str.substr(str.length - 52);
    switch (x) {
        case 0:
            //zero, do nothing, ignore negative zero and subnormals
            break;
        case 0xFF:
            if (m) fval = NaN;
            else if (s > 0) fval = Number.POSITIVE_INFINITY;
            else fval = Number.NEGATIVE_INFINITY;
            break;
        default:
            let delta = 1.0;
            for (let i = 0; i < m.length; i++) {
                delta += parseInt(m[i]) * Math.pow(2, -1 * (i + 1))
            }

            fval = s * Math.pow(2, x - 0x3ff) * delta;
            break;
    }
    return fval;
}


Bytecode.handle_fcmpg = function () {
}

Bytecode.handle_dcmpl = function () {

    let ia = (frameData.operand_stack.pop() >>> 0).toString(2) + (frameData.operand_stack.pop() >>> 0).toString(2);
    let ib = (frameData.operand_stack.pop() >>> 0).toString(2) + (frameData.operand_stack.pop() >>> 0).toString(2);
    let a = Bytecode.ieee64StrToDouble(ia);
    let b = Bytecode.ieee64StrToDouble(ib);

    if (a > b) frameData.operand_stack.push(1);
    else if (a < b) frameData.operand_stack.push(-1);
    else frameData.operand_stack.push(0);

    _program_counter.increment();
}

Bytecode.handle_dcompg = function () {


}

Bytecode.handle_ifeq = function () {
    const delta = _program_counter.next() << 8 | _program_counter.next();
    let i = frameData.operand_stack.pop();


    if (i == 0) {
        //两者应该是等效的
        // _program_counter.set(delta +_program_counter.ptr- 2);
        _program_counter.increment(delta - 2);
    } else {
        _program_counter.increment();
    }


}

Bytecode.handle_ifne = function () {
}

Bytecode.handle_iflt = function () {
}

Bytecode.handle_ifge = function () {
}

Bytecode.handle_ifgt = function () {
}

Bytecode.handle_ifle = function () {
}

Bytecode.handle_if_icmpeq = function () {
    //这个获取的应该是距离当前code position的差值
    const delta = _program_counter.next() << 8 || _program_counter.next();
    const a = frameData.operand_stack.pop();
    const b = frameData.operand_stack.pop();
    if (a == b) {
        //所以跳转的位置要加上当前位置
        //-2 是因为上面调用了2次next 读了2个
        _program_counter.set(delta + _program_counter.ptr - 2);
    } else {
        _program_counter.increment();
    }

}

Bytecode.handle_if_icmpne = function () {
}

Bytecode.handle_if_icmplt = function () {
}

Bytecode.handle_if_icmpge = function () {
}

Bytecode.handle_if_icmpgt = function () {
}

Bytecode.handle_if_icmple = function () {
}

Bytecode.handle_if_acmpeq = function () {
}

Bytecode.handle_if_acmpne = function () {
}

Bytecode.handle_goto = function () {
}

Bytecode.handle_jsr = function () {
}

Bytecode.handle_ret = function () {
}

Bytecode.handle_tableswitch = function () {
}

Bytecode.handle_lookupswitch = function () {
}

Bytecode.handle_ireturn = function () {
    let last = frameData.lastFrame;
    _program_counter = frameData.return_pc;

    let i = frameData.operand_stack.pop();
    last.operand_stack.push(i);
    frameData = last;
    //当前frameData的return_pc 记录的是上一个方法的_program_counter
    _program_counter.increment();
}

Bytecode.handle_lreturn = function () {
}

Bytecode.handle_freturn = function () {
}

Bytecode.handle_dreturn = function () {
}

Bytecode.handle_areturn = function () {
}

Bytecode.handle_return = function () {
    //无结果返回
    _program_counter.increment();
}

Bytecode.handle_getstatic = function () {
    const i = _program_counter.next() << 8 || _program_counter.next();

    const thisClass = Bytecode.currentClass();
    const fieldRef = thisClass.constantPool[i];
    const classInfo = thisClass.constantPool[fieldRef.classIndex];
    const className = thisClass.constantPool[classInfo.nameIndex];

    const nameType = thisClass.constantPool[fieldRef.nameAndTypeIndex];
    const name = thisClass.constantPool[nameType.nameIndex];
    const desc = thisClass.constantPool[nameType.descriptorIndex];

    const targetClass = loader.load(className);

    const field = targetClass.getField(name, desc);
    if (field == null) {
        console.log("field not found");
    }

    if ((field & JD.AccessFlag.STATIC) != 0) {
        console.log("file is not static");
    }

    const variable = field.get();

    if (variable.type == 'D' || variable.type == 'J') {
        //lowBytes
        frameData.operand_stack.push(variable.value[0]);
        //highBytes
        frameData.operand_stack.push(variable.value[1]);
    } else {
        //variable should not be null
        //因为在put内部反了一下  所以这里取后面的那个
        frameData.operand_stack.push(variable.value[1]);
    }

    _program_counter.increment();
}

Bytecode.handle_putstatic = function () {
    const i = _program_counter.next() << 8 || _program_counter.next();

    const thisClass = Bytecode.currentClass();
    const fieldRef = thisClass.constantPool[i];
    const classInfo = thisClass.constantPool[fieldRef.classIndex];
    const className = thisClass.constantPool[classInfo.nameIndex];

    const nameType = thisClass.constantPool[fieldRef.nameAndTypeIndex];
    const name = thisClass.constantPool[nameType.nameIndex];
    const desc = thisClass.constantPool[nameType.descriptorIndex];

    const targetClass = loader.load(className);

    const field = targetClass.getField(name, desc);
    if (field == null) {
        console.log("field not found");
    }

    if ((field & JD.AccessFlag.STATIC) != 0) {
        console.log("file is not static");
    }

    console.log(desc)

    //todo 处理 2 位长的情况                          highbytes                     lowbytes
    //double 和 long 的情况
    let variable = null;
    if (desc.stringValue == 'D' || desc.stringValue == 'J') {
        console.log("two word long")
        variable = new Variable(desc.stringValue, frameData.operand_stack.pop(), frameData.operand_stack.pop());
    } else {
        variable = new Variable(desc.stringValue, frameData.operand_stack.pop());
    }

    field.set(variable);

    _program_counter.increment();
}

Bytecode.handle_getfield = function () {
    //Todo: getField
    //实现getField/putField，可以对对象的表示，field与位移的关系，
    //field之间的顺序等有个确定的策略

}

Bytecode.handle_putfield = function () {

}

Bytecode.handle_invokevirtual = function () {
}

Bytecode.handle_invokespecial = function () {
}

Bytecode.handle_invokestatic = function () {
    let i = _program_counter.next() << 8 || _program_counter.next();
    let javaClass = Bytecode.currentClass();

    let methodRef = javaClass.constantPool[i];
    let classInfo = javaClass.constantPool[methodRef.classIndex];
    let className = javaClass.constantPool[classInfo.nameIndex];

    let nameAndType = javaClass.constantPool[methodRef.nameAndTypeIndex];
    let name = javaClass.constantPool[nameAndType.nameIndex];
    let type = javaClass.constantPool[nameAndType.descriptorIndex];

    // console.log("--------------------------------")
    // console.log("methodRef")
    // console.log(methodRef);
    // console.log("classInfo")
    // console.log(classInfo);
    // console.log("className")
    // console.log(className);
    // console.log("name")
    // console.log(name);
    // console.log("type")
    // console.log(type);
    // console.log("--------------------------------")


    //用classloader加载目标类
    let clazz = loader.load(className);
    //查找目标方法
    let method = clazz.getMethod(name, type);
    //检查访问控制
    //调用新方法,创建新frameData

    // console.log(method);
    frameData = new FrameData(method.attributes[0], clazz, _program_counter, frameData, true);

    //新的_program_counter  所以全部初始化
    _program_counter = new Program_counter();
    _program_counter.code = method.attributes[0].code;
    _program_counter.ptr = 0;
    // _program_counter.increment();
}

Bytecode.handle_invokeinterface = function () {
}

Bytecode.handle_new = function () {

}

Bytecode.handle_newarray = function () {
}

Bytecode.handle_anewarray = function () {
}

Bytecode.handle_arraylength = function () {
}

Bytecode.handle_athrow = function () {
}

Bytecode.handle_checkcast = function () {
}

Bytecode.handle_instanceof = function () {
}

Bytecode.handle_monitorenter = function () {
}

Bytecode.handle_monitorexit = function () {
}

Bytecode.handle_wide = function () {
}

Bytecode.handle_multianewarray = function () {
}

Bytecode.handle_ifnull = function () {
}

Bytecode.handle_ifnonnull = function () {
}

Bytecode.handle_goto_w = function () {
}

Bytecode.handle_jsr_w = function () {
}

Bytecode.handle_breakpoint = function () {
}

Bytecode.handle_impdep1 = function () {
}

Bytecode.handle_impdep2 = function () {
}


Bytecode.init_stack = function (size) {
    //todo
    // let stack = [];
    // if (stack == null) {
    //     return false;
    // }
    // _stack_bottom = stack;
    // _stack_top = _stack_bottom + size;
    // _stack_ptr = _stack_top;
    // _frame_data_ptr = null;
    // return true;
}


Bytecode.push_int = function (x) {
    //Bytecode.check_stack_pointer(_stack_ptr);
    frameData.operand_stack.push(x);
}

Bytecode.pop_int = function () {
    //check_stack_pointer(_stack_ptr);
    return frameData.operand_stack.pop();
}


Bytecode.check_stack_pointer = function () {
    console.log("stack pointer overflow");
    return false;
}


Bytecode.currentClass = function () {
    return frameData.theClass;
}

var Bytecode = Bytecode || {};


class FrameData {
    constructor(attr, clazz, return_pc, lastFrame, isStatic) {
        this.isStatic = isStatic || false;
        this.local_variables = new Array(attr.maxLocals);
        this.operand_stack = [];    //new Array(attr.maxStack);
        this.theClass = clazz;
        this.return_pc = return_pc;// _program_counter.ptr; //记录上一个frame的执行位置
        this.lastFrame = lastFrame;

        //不为null说明是方法调用,把上一个栈帧中操作数栈中数据放到局部变量表中
        if (lastFrame != null) {
            let i = 0;
            if (!this.isStatic) {
                //非静态调用则第0个是this引用
                this.local_variables[i++] = this.theClass;
            }
            lastFrame.operand_stack.forEach(e => this.local_variables[i++] = e);
        }

    }

}


// Bytecode.run = function (classfullname) {
//     const constMethodName = "main";
//     const constMethodDesc = "()V";   //为了简单，暂时我们假设main方法没有参数
//
//     let mainClass =
//     var stream = new JD.Stream(str);
//     var classFile = new JD.ClassFile(stream);
//     assert_exception(mainClass != NULL, "class not found");
//     MethodInfo *methodInfo = mainClass->getMethod(methodNameInfo, methodDescInfo);
// }

var table = [];
var frameData;
var loader;
var _program_counter = new Program_counter();
Bytecode.run2 = function (classfullname) {

    Bytecode.init_bytecode_handler_table(table);


    const constMethodName = "main";
    const constMethodDesc = "()V";   //为了简单，暂时我们假设main方法没有参数

    loader = new ClassLoader();
    // let stream = new JD.Stream(str);

    const mainClassName = new Utf8Info(JD.ConstantPoolTag.CLASS, classfullname.length, classfullname);
    var mainClass = loader.load(mainClassName);

    console.log(mainClass);
    // console.log("--------------------")

    let main = new Utf8Info(JD.ConstantPoolTag.UTF8, constMethodName.length, constMethodName);
    let desc = new Utf8Info(JD.ConstantPoolTag.UTF8, constMethodDesc.length, constMethodDesc);

    if (mainClass == null) {
        console.log("mainClass not found");
    }

    //mainClass.constantPool.forEach(pool => console.log(pool));
    // let i = 0;
    // mainClass.constantPool.forEach(pool => {
    //         // console.log(i++)
    //         console.log(pool)
    //     }
    // );


    let method = mainClass.getMethod(main, desc);

    // console.log(method)
    // method.attributes.forEach(attr => console.log(attr))

    let attribute = method.attributes[0];
    frameData = new FrameData(attribute, mainClass, null, null);

    _program_counter.code = method.attributes[0].code;
    // console.log(_program_counter.code);
    Bytecode.execute();

}


Bytecode.execute = function () {

    // _program_counter.first();
    let count = 0;
    while (true) {
        count++;

        if (count > 1000) {
            console.log("stackoverflow");
            break;
        }
        if (_program_counter.current() == undefined) break;

        let handler = table[_program_counter.current()].handler;
        // console.log(_program_counter.current());
        console.log(table[_program_counter.current()]);
        handler();
    }

    console.log(frameData.local_variables[0]);
}


